/*
 * CachedImage.java
 *
 * Created on January 10, 2008, 5:50 PM
 */

package picto.core;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import picto.io.*;
import picto.util.Resources;

/**
 * 
 * @author davedes
 */
public class CachedImage extends ArchivableImage {
    
    private static HashMap<String, BufferedImage> cache = new HashMap<String, BufferedImage>();
    
    /** 
     * Creates a new cached image using the specified unique reference. If the image data has 
     * previously been loaded through using CachedImage, then this image is set up with the
     * cached data.
     */
    public CachedImage(String reference) {
        this(reference, (BufferedImage)null);
    }
    
    /**
     * Creates a new cached image using the specified unique reference and the given 
     * image to cache. If a cached image already exists under this reference, it is 
     * replaced by the given image. If the specified image is null, the cached image
     * will be used if it exists.
     */
    public CachedImage(String reference, BufferedImage image) {
        super();
        if (reference==null||reference.length()==0)
            throw new IllegalArgumentException("cannot have null or empty ref");
        this.reference = reference;
        
        if (image!=null) { //given image exists, use that
            this.image = image;
            this.g2d = image.createGraphics();
        } else { //use cached image
            BufferedImage i2 = getCachedImage(reference);
            if (i2!=null) {
                this.image = i2;
                this.g2d = i2.createGraphics();
            }
        }
        
        if (this.image!=null)
            putCachedImage(this.reference, this.image);
    }
    
    public CachedImage(String reference, String path) throws IOException {
        this(reference, ImageIO.read(Resources.getResourceAsStream(path)));
    }
    
    protected static CachedImage readCachedImage(
                ArchiveReader reader, Element root, String refDefault) throws ArchiveException {
        NodeList nl = root.getChildNodes();
        for (int i=0; i<nl.getLength(); i++) {
            Node n = nl.item(i);
            if (n instanceof Element && "image-data".equals(n.getNodeName())) {
                Element e = (Element)n;
                String ref = e.getAttribute("ref");
                if (ref.length()==0)
                    ref = refDefault;
                CachedImage t2 = new CachedImage(ref);
                t2.read(reader, e);
                return t2;
            }
        }
        return null;
    }
    
    protected BufferedImage getCachedImage(String reference) {
        return cache.get(reference);
    }
    
    protected BufferedImage putCachedImage(String reference, BufferedImage image) {
        return cache.put(reference, image);
    }
    
    public void setImage(BufferedImage image) {
        super.setImage(image);
        putCachedImage(getReference(), image);
    }
    
    public void setReference(String reference) {
        String old = getReference();
        cache.remove(old);
        super.setReference(reference);
        putCachedImage(reference, getImage());
    }
    
    private String getNextReference(String old) {
        int num = 1;
        while ( cache.containsKey(old+"_"+num) ) {
            num++;
        }
        return old+"_"+num;
    }
    
    public ArchivableImage clone() {
        String nextRef = getNextReference(getReference());
        
        //creates a cached image (will not have a buffered image attached)
        CachedImage image = new CachedImage(nextRef);
        image.image = this.image;
        image.g2d = this.g2d;
        image.setFormat(this.getFormat());
        return image;
    }
}
